#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <utils.h>
#include <lobe.h>
#include <time.h>
#include <dbg.h>

using namespace std;

#define THRESHOLD 0.00001
#define MAXITER   0xFFFFF

dVec2d_t ipData, opData;
lobe * bpLobe;

bool testLobe () {
  forEach (i, 0, opData.size())
    if (THRESHOLD < myMse(opData[i], bpLobe->getOutput(ipData[i]))) return 0;
  return 1;
}

int main() {
  unsigned seed = time(NULL);
  cout << "Using seed " << seed << "\n";
  srand(seed);

  unsigned ipCnt, opCnt;
  cin >> ipCnt >> opCnt;

  // Decide architecture
  uiVec_t arch;
  arch.push_back (ipCnt);
  arch.push_back (ipCnt<<1);
  //arch.push_back (ipCnt);
  arch.push_back (opCnt);

  // Create network
  bpLobe = new lobe(arch);
  bpLobe->show();

  unsigned n;
  cin >> n;

  double buf;

  forEach (i, 0, n) {
    ipData.push_back(dVec_t());
    opData.push_back(dVec_t());

    forEach (j, 0, ipCnt) {
      cin >> buf;
      ipData[i].push_back(buf);
    }

    forEach (j, 0, opCnt) {
      cin >> buf;
      opData[i].push_back(buf);
    }
  }

  dVec_t op;

  cout << "Before Training\n";
  forEach (x, 0, n) {
    op = bpLobe->getOutput(ipData[x]);
    assert (op.size() == opCnt);
    showdVec ("op", op);
  }
  cout << string(100, '-') << "\n";

  forEach (x, 0, MAXITER) {
    bpLobe->train(ipData[x%n], opData[x%n]);
    //bpLobe->show();
    if (testLobe()) {
      cout << "Achieved in " << x << " iterations\n";
      break;
    }
  }

  cout << "After Training\n";
  forEach (x, 0, n) {
    op = bpLobe->getOutput(ipData[x]);
    assert (op.size() == opCnt);
    showdVec ("op", op);
  }

  bpLobe->show();
  return 0;
}
